"""
Seaborn 多维度数据可视化示例

知识点：
1. 同时使用 hue、size、style 展示多个维度
2. 自定义 sizes 范围优化视觉效果
3. 使用 legend 参数控制图例显示
4. 处理多维度数据的最佳实践
5. 避免信息过载的技巧
"""

import seaborn as sns
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

# 先设置 seaborn 主题
sns.set_theme(style="whitegrid")

# 然后强制设置中文字体（必须在 set_theme 之后）
plt.rcParams['font.sans-serif'] = ['PingFang HK', 'Hiragino Sans GB', 'STHeiti', 'Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['font.family'] = 'sans-serif'

# 创建汽车数据集
np.random.seed(42)
n = 150

brands = ['品牌A', '品牌B', '品牌C']
fuel_types = ['汽油', '柴油', '电动']
car_types = ['轿车', 'SUV', '跑车']

data = []
for _ in range(n):
    brand = np.random.choice(brands)
    fuel = np.random.choice(fuel_types)
    car_type = np.random.choice(car_types)
    
    # 根据类型设置基础值
    base_power = {'轿车': 150, 'SUV': 200, '跑车': 300}[car_type]
    base_price = {'轿车': 20, 'SUV': 30, '跑车': 50}[car_type]
    base_fuel_consumption = {'汽油': 8, '柴油': 7, '电动': 0}[fuel]
    
    power = base_power + np.random.normal(0, 30)
    price = base_price + power * 0.1 + np.random.normal(0, 5)
    fuel_consumption = base_fuel_consumption + power * 0.01 + np.random.normal(0, 1)
    weight = 1200 + power * 2 + np.random.normal(0, 100)
    
    data.append({
        '品牌': brand,
        '燃料类型': fuel,
        '车型': car_type,
        '马力(HP)': max(80, power),
        '价格(万元)': max(10, price),
        '油耗(L/100km)': max(0, fuel_consumption),
        '重量(kg)': max(1000, weight)
    })

df = pd.DataFrame(data)

# 创建多子图展示不同的多维度组合
fig = plt.figure(figsize=(18, 12))
fig.suptitle('多维度数据可视化最佳实践', fontsize=16, fontweight='bold', y=0.995)

# 1. 二维基础图（作为对比）
ax1 = plt.subplot(2, 3, 1)
sns.scatterplot(
    data=df,
    x='马力(HP)',
    y='价格(万元)',
    s=100,
    alpha=0.6,
    ax=ax1
)
ax1.set_title('1. 二维基础图\n（马力 vs 价格）', fontweight='bold')

# 2. 添加 hue（三维）
ax2 = plt.subplot(2, 3, 2)
sns.scatterplot(
    data=df,
    x='马力(HP)',
    y='价格(万元)',
    hue='车型',
    s=100,
    alpha=0.7,
    palette='Set2',
    ax=ax2
)
ax2.set_title('2. 添加 hue 维度\n（+ 车型分类）', fontweight='bold')

# 3. 添加 size（四维）
ax3 = plt.subplot(2, 3, 3)
sns.scatterplot(
    data=df,
    x='马力(HP)',
    y='价格(万元)',
    hue='车型',
    size='重量(kg)',
    sizes=(50, 400),
    alpha=0.6,
    palette='Set2',
    ax=ax3
)
ax3.set_title('3. 添加 size 维度\n（+ 重量）', fontweight='bold')

# 4. 添加 style（五维）
ax4 = plt.subplot(2, 3, 4)
sns.scatterplot(
    data=df,
    x='马力(HP)',
    y='价格(万元)',
    hue='车型',
    size='重量(kg)',
    style='燃料类型',
    sizes=(50, 400),
    alpha=0.7,
    palette='Set2',
    ax=ax4
)
ax4.set_title('4. 添加 style 维度\n（+ 燃料类型）', fontweight='bold')

# 5. 优化版本：调整透明度和大小范围
ax5 = plt.subplot(2, 3, 5)
sns.scatterplot(
    data=df,
    x='马力(HP)',
    y='价格(万元)',
    hue='车型',
    size='重量(kg)',
    style='燃料类型',
    sizes=(80, 300),  # 调整大小范围
    alpha=0.65,  # 优化透明度
    palette='husl',  # 更鲜明的配色
    edgecolor='white',  # 添加白色边框
    linewidth=0.5,
    ax=ax5
)
ax5.set_title('5. 优化版本\n（调整透明度和边框）', fontweight='bold')

# 6. 分面 + 多维度
ax6 = plt.subplot(2, 3, 6)
# 只展示一个车型以简化
sedan_data = df[df['车型'] == '轿车']
sns.scatterplot(
    data=sedan_data,
    x='马力(HP)',
    y='油耗(L/100km)',
    hue='品牌',
    size='价格(万元)',
    style='燃料类型',
    sizes=(80, 300),
    alpha=0.7,
    palette='Set1',
    ax=ax6
)
ax6.set_title('6. 聚焦分析\n（仅轿车：马力 vs 油耗）', fontweight='bold')

plt.tight_layout()
plt.savefig('/Users/binming/Desktop/CodeBase/python/Python语法/1-常用库/1-数据分析/Seaborn关系图示例/4-1-多维度对比.png', 
            dpi=300, bbox_inches='tight')
plt.show()

# 创建第二组图：展示不同的多维度组合策略
fig2, axes = plt.subplots(2, 2, figsize=(16, 12))
fig2.suptitle('多维度可视化策略对比', fontsize=16, fontweight='bold')

# 策略1: hue + size（推荐用于连续变量）
sns.scatterplot(
    data=df,
    x='马力(HP)',
    y='价格(万元)',
    hue='重量(kg)',  # 连续变量用颜色渐变
    size='油耗(L/100km)',
    sizes=(50, 300),
    palette='viridis',  # 渐变色
    alpha=0.7,
    ax=axes[0, 0]
)
axes[0, 0].set_title('策略1: 连续变量用 hue + size\n（重量用颜色，油耗用大小）', fontweight='bold')

# 策略2: hue + style（推荐用于分类变量）
sns.scatterplot(
    data=df,
    x='马力(HP)',
    y='价格(万元)',
    hue='车型',
    style='燃料类型',
    s=150,
    alpha=0.7,
    palette='Set2',
    ax=axes[0, 1]
)
axes[0, 1].set_title('策略2: 分类变量用 hue + style\n（车型用颜色，燃料用形状）', fontweight='bold')

# 策略3: 使用 size 表示重要的数值维度
sns.scatterplot(
    data=df,
    x='马力(HP)',
    y='油耗(L/100km)',
    hue='燃料类型',
    size='价格(万元)',  # 价格作为重要维度
    sizes=(100, 500),
    alpha=0.6,
    palette='Set1',
    ax=axes[1, 0]
)
axes[1, 0].set_title('策略3: 突出关键数值维度\n（价格用大小强调）', fontweight='bold')

# 策略4: 综合应用（最复杂但信息最丰富）
scatter = sns.scatterplot(
    data=df,
    x='马力(HP)',
    y='价格(万元)',
    hue='车型',
    size='重量(kg)',
    style='燃料类型',
    sizes=(80, 350),
    alpha=0.65,
    palette='deep',
    edgecolor='gray',
    linewidth=0.5,
    ax=axes[1, 1]
)
axes[1, 1].set_title('策略4: 综合应用（5个维度）\n（需要仔细设计以避免混乱）', fontweight='bold')

plt.tight_layout()
plt.savefig('/Users/binming/Desktop/CodeBase/python/Python语法/1-常用库/1-数据分析/Seaborn关系图示例/4-2-多维度策略.png', 
            dpi=300, bbox_inches='tight')
plt.show()

# 输出数据统计信息
print("=" * 70)
print("多维度可视化最佳实践总结")
print("=" * 70)
print("\n1. 维度选择原则：")
print("   - X/Y 轴: 最重要的两个连续变量")
print("   - hue: 最重要的分类变量（或连续变量用渐变色）")
print("   - size: 次要的连续变量")
print("   - style: 次要的分类变量（通常不超过3-4个类别）")

print("\n2. 避免信息过载：")
print("   - 不要同时使用超过5个维度")
print("   - 确保每个维度都有明确的意义")
print("   - 使用透明度处理重叠问题")
print("   - 添加边框提高可读性")

print("\n3. 参数优化建议：")
print("   - sizes: (50, 400) 适合大多数场景")
print("   - alpha: 0.6-0.8 之间")
print("   - 添加 edgecolor 和 linewidth 增强对比")

print("\n4. 配色方案选择：")
print("   - 分类变量: Set1, Set2, Set3, Paired")
print("   - 连续变量: viridis, plasma, coolwarm")
print("   - 色盲友好: colorblind palette")

print("\n" + "=" * 70)
print("数据集统计信息：")
print("=" * 70)
print(df.groupby(['车型', '燃料类型']).size().unstack(fill_value=0))
print(f"\n总样本数: {len(df)}")
print(f"马力范围: {df['马力(HP)'].min():.0f} - {df['马力(HP)'].max():.0f} HP")
print(f"价格范围: {df['价格(万元)'].min():.1f} - {df['价格(万元)'].max():.1f} 万元")
print(f"重量范围: {df['重量(kg)'].min():.0f} - {df['重量(kg)'].max():.0f} kg")
